package org.ourgrid.broker.business.schedulerdata.executor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.ourgrid.broker.business.schedulerdata.SchedulerData;
import org.ourgrid.broker.response.LWPHereIsJobStatsResponseTO;
import org.ourgrid.broker.status.GridProcessStatusInfo;
import org.ourgrid.broker.status.GridProcessStatusInfoResult;
import org.ourgrid.broker.status.JobStatusInfo;
import org.ourgrid.broker.status.TaskStatusInfo;
import org.ourgrid.broker.status.WorkerStatusInfo;
import org.ourgrid.common.executor.ExecutorResult;
import org.ourgrid.common.interfaces.to.GridProcessHandle;
import org.ourgrid.common.internal.IResponseTO;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class HereIsJobStatsExecutor extends AbstractSchedulerDataExecutor {
	
	
	/**
	 * <HERE_IS_JOB_STATS jobId='int' jobState='int' creationTime='long' finalizationTime='long'>
	 * 
	 * 		1..n <TASK_STATS taskId='int' jobId='int' taskState='String' actualFails='int' 
	 * 				creationTime='long' finalizationTime='long'>
	 * 
	 * 			 1..n <GRID_PROCESS_STATS processId='int' taskId='int' jobId='int' processState='String' 
	 * 					processPhase='String' workerInfo='String' creationTime='long' finalizationTime='long'> 
	 * 						
	 * 				  		<RESULT executionError='String' executionErrorCause='String' initDataTime='long'
	 * 						 remoteDataTime='long' finalDataTime='long' exitValue='int' stderr='String' stdout='String'
	 * 						 sabotageCheck='String'/>
	 * 
	 * 				  </GRID_PROCESS_STATS>
	 * 
	 * 			 </TASK_STATS>
	 * 			
	 * 		1..n <PEER_TO_REPORT peerId='String' requestId='long'/>
	 * 
	 * </HERE_IS_JOB_STATS> 
	 * 
	 */
	/* (non-Javadoc)
	 * @see org.ourgrid.broker.business.schedulerdata.executor.SchedulerDataExecutorIF#execute(org.ourgrid.broker.business.schedulerdata.SchedulerData)
	 */
	public List<IResponseTO> execute(SchedulerData command) {
		List<IResponseTO> responses = new ArrayList<IResponseTO>();
		
		Document logDocFile = super.getXMl(command.getXml());
		Element element = logDocFile.getDocumentElement();
		
		JobStatusInfo jobInfo = new JobStatusInfo();
		
		int jobId = Integer.valueOf(element.getAttribute("jobId"));
		int jobState = Integer.valueOf(element.getAttribute("jobState"));
		long jobCreationTime = Long.valueOf(element.getAttribute("creationTime"));
		long jobFinalizationTime = Long.valueOf(element.getAttribute("finalizationTime"));
		
		jobInfo.setJobID(jobId);
		jobInfo.setState(jobState);
		jobInfo.setCreationTime(jobCreationTime);
		jobInfo.setFinalizationTime(jobFinalizationTime);
		
		List<TaskStatusInfo> tasksInfos = new ArrayList<TaskStatusInfo>();
		
		NodeList taskNodeList = element.getElementsByTagName("TASK_STATS");
		for (int i = 0; i < taskNodeList.getLength(); i++) {
			
			NamedNodeMap taskAttributes = taskNodeList.item(i).getAttributes();
			int taskId = Integer.valueOf(taskAttributes.getNamedItem("taskId").getNodeValue());
			int taskJobId = Integer.valueOf(taskAttributes.getNamedItem("jobId").getNodeValue());
			int taskActualFails = Integer.valueOf(taskAttributes.getNamedItem("actualFails").getNodeValue());
			String taskState = taskAttributes.getNamedItem("taskState").getNodeValue();
			long taskCreationTime = Long.valueOf(taskAttributes.getNamedItem("creationTime").getNodeValue());
			long taskFinalizationTime = Long.valueOf(taskAttributes.getNamedItem("finalizationTime").getNodeValue());
			
			TaskStatusInfo taskInfo = new TaskStatusInfo();
			taskInfo.setId(taskId);
			taskInfo.setJobID(taskJobId);
			taskInfo.setActualFails(taskActualFails);
			taskInfo.setState(taskState);
			taskInfo.setCreationTime(taskCreationTime);
			taskInfo.setFinalizationTime(taskFinalizationTime);
			
			tasksInfos.add(taskInfo);
			
			List<GridProcessStatusInfo> processesInfos = new ArrayList<GridProcessStatusInfo>();
			
			NodeList taskChildNodes = taskNodeList.item(i).getChildNodes();
			for (int j = 0; j < taskChildNodes.getLength(); j++) {
				Node taskChildNode = taskChildNodes.item(j);
				
				if (!taskChildNode.getNodeName().equals("GRID_PROCESS_STATS")) {
					continue;
				}
				
				NamedNodeMap processAttributes = taskChildNode.getAttributes();
				int processId = Integer.valueOf(processAttributes.getNamedItem("processId").getNodeValue());
				int processTaskId = Integer.valueOf(processAttributes.getNamedItem("taskId").getNodeValue());
				int processJobId = Integer.valueOf(processAttributes.getNamedItem("jobId").getNodeValue());
				String processState = processAttributes.getNamedItem("processState").getNodeValue();
				String processPhase = processAttributes.getNamedItem("processPhase").getNodeValue();
				String workerInfo = processAttributes.getNamedItem("workerInfo").getNodeValue();
				long processCreationTime = Long.valueOf(processAttributes.getNamedItem("creationTime").getNodeValue());
				long processFinalizationTime = Long.valueOf(processAttributes.getNamedItem("finalizationTime").getNodeValue());
				
				NodeList processChildNodes = taskChildNode.getChildNodes();
				Node resultNode = null;
				for (int k = 0; k < processChildNodes.getLength(); k++) {
					if (processChildNodes.item(k).getNodeName().equals("RESULT")) {
						resultNode = processChildNodes.item(k);
						break;
					}
				}
				
				NamedNodeMap resultAttributes = resultNode.getAttributes();
				
				String executionError = resultAttributes.getNamedItem("executionError").getNodeValue();
				String executionErrorCause = resultAttributes.getNamedItem("executionErrorCause").getNodeValue();
				
				Node exitValueNode = resultAttributes.getNamedItem("exitValue");
				int exitValue = exitValueNode == null ? -1 : Integer.valueOf(exitValueNode.getNodeValue());
				
				long initDataTime = Long.valueOf(resultAttributes.getNamedItem("initDataTime").getNodeValue());
				long remoteDataTime = Long.valueOf(resultAttributes.getNamedItem("remoteDataTime").getNodeValue());
				long finalDataTime = Long.valueOf(resultAttributes.getNamedItem("finalDataTime").getNodeValue());
				String sabotageCheck = resultAttributes.getNamedItem("sabotageCheck").getNodeValue();
				
				String stderr = "";
				String stdout = "";
				
				for (int l = 0; l < resultNode.getChildNodes().getLength(); l++) {
					Node childNode = resultNode.getChildNodes().item(l);
					if (childNode.getNodeName().equals("stderr")) {
						stderr = childNode.getNodeValue();
					} else if (childNode.getNodeName().equals("stdout")) {
						stdout = childNode.getNodeValue();
					}
				}
				
				GridProcessHandle processHandle = new GridProcessHandle(processJobId, processTaskId, processId);
				
				GridProcessStatusInfo processInfo = new GridProcessStatusInfo();
				processInfo.setId(processId);
				processInfo.setJobID(processJobId);
				processInfo.setTaskID(processTaskId);
				processInfo.setState(processState);
				processInfo.setPhase(processPhase);
				processInfo.setHandle(processHandle);
				processInfo.setCreationTime(processCreationTime);
				processInfo.setFinalizationTime(processFinalizationTime);
				
				WorkerStatusInfo workerStatusInfo = new WorkerStatusInfo();
				workerStatusInfo.setProcessState(processState);
				workerStatusInfo.setWorkerID(workerInfo);
				workerStatusInfo.setReplicaHandle(processHandle);
				processInfo.setWorkerInfo(workerStatusInfo);
				
				ExecutorResult executorResult = new ExecutorResult(exitValue, stdout, stderr);
				
				GridProcessStatusInfoResult processResult = new GridProcessStatusInfoResult(
						executionError, executionErrorCause, initDataTime, 
						remoteDataTime, finalDataTime, executorResult);
				processResult.setSabotageCheck(sabotageCheck);
				
				processInfo.setReplicaResult(processResult);
				
				processesInfos.add(processInfo);
			}
			
			taskInfo.setGridProcesses(processesInfos);
		}
		
		jobInfo.setTasks(tasksInfos);
		
		Map<String, Long> peersIdToRequests = new TreeMap<String, Long>();
		
		NodeList peerNodeList = element.getElementsByTagName("PEER_TO_REPORT");
		for (int i = 0; i < peerNodeList.getLength(); i++) {
			String peerId = peerNodeList.item(i).getAttributes().getNamedItem("peerId").getNodeValue();
			Long requestId = Long.valueOf(peerNodeList.item(i).getAttributes().getNamedItem("requestId").getNodeValue());
			
			peersIdToRequests.put(peerId, requestId);
		}
		
		jobInfo.setPeersToRequests(peersIdToRequests);
		
		LWPHereIsJobStatsResponseTO response = new LWPHereIsJobStatsResponseTO();
		response.setJobStatusInfo(jobInfo);
		
		responses.add(response);
		
		return responses;
	}

}
